package com.cscec5b.inspection.config;

import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.RSASSASigner;
import com.nimbusds.jose.crypto.RSASSAVerifier;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
import org.springframework.stereotype.Service;

import java.text.ParseException;
import java.time.Instant;
import java.util.Date;
import java.util.List;
import java.util.Optional;

@Service
public class JwtService {
    private final KeyManager keyManager;
    private final AppProperties props;

    public JwtService(KeyManager keyManager, AppProperties props) {
        this.keyManager = keyManager; this.props = props;
    }

    // 签发token
    public String issueToken(String clientId, List<String> scopes) {
        try {
            Instant now = Instant.now();
            JWTClaimsSet claims = new JWTClaimsSet.Builder()
                    .issuer("inspection-app")
                    .subject(clientId)
                    .audience("users-sync-api")
                    .issueTime(Date.from(now))
                    .expirationTime(Date.from(now.plusSeconds(props.getTokenTtlSeconds())))
                    .claim("scope", String.join(" ", scopes))
                    .build();

            JWSHeader header = new JWSHeader.Builder(JWSAlgorithm.RS256)
                    .keyID(keyManager.keyId())
                    .type(JOSEObjectType.JWT)
                    .build();

            SignedJWT jwt = new SignedJWT(header, claims);
            jwt.sign(new RSASSASigner(keyManager.privateKey()));
            return jwt.serialize();
        } catch (Exception e) {
            throw new RuntimeException("issue token failed", e);
        }
    }

    /** 解析并校验签名，返回 Claims */
    public JWTClaimsSet parseAndValidate(String token) {
        try {
            SignedJWT jwt = SignedJWT.parse(token);
            // 如已在过滤器里做过校验，也可以只 parse 不 verify；这里给出带验签的写法
            var verifier = new RSASSAVerifier(keyManager.publicKey());
            if (!jwt.verify(verifier)) {
                throw new RuntimeException("无效的 JWT 签名");
            }
            JWTClaimsSet claims = jwt.getJWTClaimsSet();

            // 过期校验（可选：也许你的 Filter 已做过）
            Date exp = claims.getExpirationTime();
            if (exp != null && new Date().after(exp)) {
                throw new RuntimeException("JWT 已过期");
            }
            return claims;
        } catch (ParseException | JOSEException e) {
            throw new RuntimeException("解析 JWT 失败", e);
        }
    }

    /** 提取 subject 作为 username（若签发时把用户名放在 sub） */
    public String extractUsername(String token) {
        return parseAndValidate(token).getSubject();
    }

    /** 尝试从多种 key 中提取 userCode；不存在则返回 empty */
    public Optional<String> extractUserCode(String token) {
        JWTClaimsSet c = parseAndValidate(token);
        Object v = c.getClaim("userCode");
        if (v == null) v = c.getClaim("user_code");
        if (v == null) v = c.getClaim("uid");   // 兜底尝试
        return Optional.ofNullable(v == null ? null : String.valueOf(v));
    }
}
